#pragma once
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <functional>
#include <string>

namespace ThreadModule
{
    // template<typename T, typename ...Args>
    // using func_t = std::function<void(T t, Args... arg)>;

    template<typename Ret, typename Arg_t>
    using func_t = std::function<Ret(const Arg_t arg)>;

    template<typename Ret, typename T>
    class Thread
    {
    public:
        Thread(func_t<Ret, T> func, T arg_data, std::string name = "non-thread")
            : _func(func), _arg_data(arg_data), _name(name)
        {
            _Start();
        }

        ~Thread(){}
    public:
        void Stop()
        {
            _stop = true;
        }

        void Join()
        {
            void* ret = nullptr;
            int n = pthread_join(_tid, &ret);
            if(n != 0)
            {
                std::cout << "error: Join::pthread_join(), return code: " << n << std::endl; 
                exit(1);   
            }
            if(ret != nullptr)
            {
                std::cout << "result = " << (long long)ret << std::endl;
            }
            std::cout << _name << " pthread join success !" << std::endl;
        }

    private:
        static void* handler(void* self)
        {
            auto p = static_cast<Thread<Ret, T>*>(self);
            return reinterpret_cast<void*>(p->_func(p->_arg_data));
        }
        bool _Start()
        {
            int n = pthread_create(&_tid, nullptr, handler, this);
            if(n == 0)
            {
                std::cout << _name << " pthread creating..." << std::endl;
                _stop = false;
                return true;
            }
            _stop = true;
            return false;
        }

    private:
        pthread_t _tid;
        std::string _name;
        func_t<Ret, T> _func;
        T _arg_data;
        bool _stop = false;
    };
}


